package org.seeplnframework.skyeye.logback.api.config;

import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import com.ctrip.framework.apollo.spring.config.ConfigPropertySource;
import com.google.common.base.Joiner;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.seeplnframework.skyeye.common.constants.SysConstant;
import org.seeplnframework.skyeye.common.util.ConfigUtils;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.web.context.support.StandardServletEnvironment;

import java.util.Set;
import java.util.stream.Collectors;


@Slf4j
public class ApolloConfigListener implements EnvironmentAware {

    @Setter
    private Environment environment;

    private String valueOfConfigKeyInAnotherNamespace(String namespace, String key) {
        try {
            if (environment instanceof StandardServletEnvironment) {
                MutablePropertySources mps = ((StandardServletEnvironment) environment).getPropertySources();
                PropertySource ps = mps.get("ApolloPropertySources");
                if (ps != null && ps instanceof CompositePropertySource) {
                    ConfigPropertySource publicPropertySource = ((CompositePropertySource) ps)
                            .getPropertySources()
                            .stream()
                            .filter(it -> it instanceof ConfigPropertySource)
                            .map(it -> (ConfigPropertySource) it)
                            .filter(it -> it.getName().equalsIgnoreCase(namespace))
                            .findFirst()
                            .orElse(null);
                    if (publicPropertySource != null) {
                        Object value = publicPropertySource.getProperty(key);
                        if (value != null) {
                            return (String) value;
                        }
                    }
                }
            }
            return "";
        } catch (Exception e) {
            log.warn("valueOfConfigKeyInAnotherNamespace occur error. key : {} namespace : {} info : {}", key, namespace, e.getMessage());
            return "";
        }
    }

    @ApolloConfigChangeListener("skyeye.properties")
    private void listenPrivateConfig(ConfigChangeEvent changeEvent) {
        for (String key : changeEvent.changedKeys()) {
            String oldValue = changeEvent.getChange(key).getOldValue();
            String newValue = changeEvent.getChange(key).getNewValue();
            /**
             * 如果是白名单的key值发生变化 变化前后的值都要与公共配置中白名单的值进行merge
             */
            if (key.equalsIgnoreCase(SysConstant.ALARM_WHITE_LIST)) {
                String whiteListInAnotherNamespace = valueOfConfigKeyInAnotherNamespace("public_skyeye_config.properties", key);
                if (StringUtils.isNotEmpty(whiteListInAnotherNamespace)) {
                    oldValue = StringUtils.isEmpty(oldValue) ? whiteListInAnotherNamespace : Joiner.on(",").join(oldValue, whiteListInAnotherNamespace);
                    newValue = StringUtils.isEmpty(newValue) ? whiteListInAnotherNamespace : Joiner.on(",").join(newValue, whiteListInAnotherNamespace);
                }
            }
            ConfigUtils.saveProperty(key, newValue);
            log.info("skyEye listenPrivateConfig change config value of key : {} from : {} to : {}", key, oldValue, newValue);
        }
    }

    @ApolloConfigChangeListener("public_skyeye_config.properties")
    private void listenPublicConfig(ConfigChangeEvent changeEvent) {
        for (String key : changeEvent.changedKeys()) {
            String oldValue = changeEvent.getChange(key).getOldValue();
            String newValue = changeEvent.getChange(key).getNewValue();
            /**
             * 如果是白名单的key值发生变化 变化前后的值都要与服务内私有配置中白名单的值进行merge
             */
            if (key.equalsIgnoreCase(SysConstant.ALARM_WHITE_LIST)) {
                String whiteListInAnotherNamespace = valueOfConfigKeyInAnotherNamespace("skyeye.properties", key);
                if (StringUtils.isNotEmpty(whiteListInAnotherNamespace)) {
                    oldValue = StringUtils.isEmpty(oldValue) ? whiteListInAnotherNamespace : Joiner.on(",").join(oldValue, whiteListInAnotherNamespace);
                    newValue = StringUtils.isEmpty(newValue) ? whiteListInAnotherNamespace : Joiner.on(",").join(newValue, whiteListInAnotherNamespace);
                }
            }
            ConfigUtils.saveProperty(key, newValue);
            log.info("skyEye listenPublicConfig change config value of key : {} from : {} to : {}", key, oldValue, newValue);
        }
    }
}
